package com.example.servlet;

import com.alibaba.fastjson.JSON;
import com.example.dao.FileInfoDaoImpl;
import com.example.model.FileInfo;
import com.example.model.Key;
import com.example.service.FileInfoService;
import com.example.service.FileInfoServiceImpl;
import com.example.util.AESUtil;
import com.example.util.AesForFile;
import com.example.util.RSAUtil;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

import javax.crypto.SecretKey;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Base64;
import java.util.List;
import java.util.UUID;

public class UploadServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 2 创建一个 DiskFileItemFactory对象
        DiskFileItemFactory factory = new DiskFileItemFactory();
        // 3 创建一个ServletFileUpload对象，该对象是上传的核心组件
        ServletFileUpload sfu = new ServletFileUpload(factory);
        // 4 解析request对象，并得到一个表单项的集合
        FileInfo fileInfo = new FileInfo();
        try {
            List<FileItem> fileItems = sfu.parseRequest(request);
            // 5 遍历该集合，集合中的每一项即为每一个表单项
            for (FileItem item : fileItems) {
                if (item.isFormField()) {
                    // 普通表单项，不是文件项
                    // 等价于以前的 request.getParameter()
                    String fieldName = item.getFieldName();
                } else {
                    // 上传表单项
                    // 获取文件名
                    String fileName = item.getName();
                    // 获取输入流
                    InputStream is = item.getInputStream();
                    // 创建输出流
                    String path = this.getServletContext().getRealPath("/WEB-INF");
                    // 设置上传路径
                    // 当前时间设置
                    long l = System.currentTimeMillis();
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
                    String createTime = sdf.format(l);
                    String uploadPath = path + "\\upload\\" + createTime;
                    // 上传时，进行加密和录入数据库
                    fileInfo.setUuid(UUID.randomUUID().toString());
                    fileInfo.setFileSize(item.getSize());
                    fileInfo.setFileType(item.getContentType());
                    fileInfo.setFileOriginName(item.getName());
                    fileInfo.setFileCreateTime(createTime);
                    fileInfo.setFilePath(uploadPath);

                    SecretKey key = null;
                    // 用来保存数字信封
                    String signature = null;
                    try {
                        // 1 AES生成
                        key = AESUtil.secretKey();
                        byte[] encoded = Base64.getEncoder().encode(key.getEncoded());
                        // 2 RSA加密encodeString
                        byte[] rsaEncoding = RSAUtil.publicEncrypt(encoded, RSAUtil.string2PublicKey(Key.publicKey));
                        byte[] rsaEncodingString = Base64.getEncoder().encode(rsaEncoding);
                        signature = new String(rsaEncodingString, StandardCharsets.UTF_8);
                    } catch (NoSuchAlgorithmException e) {
                        e.printStackTrace();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    // 将加密后的数字信封存入fileInfo
                    fileInfo.setFileSignature(signature);
                    FileInfoService fileInfoService = new FileInfoServiceImpl(new FileInfoDaoImpl());
                    fileInfoService.insertFileInfo(fileInfo);

                    File file = new File(uploadPath, fileInfo.getUuid());
                    // 创建父目录和文件
                    if (!file.getParentFile().exists()) {
                        file.getParentFile().mkdirs();
                        file.createNewFile();
                    }
                    FileOutputStream fos = new FileOutputStream(file);

                    // 调用AES加密文件方法
                    AesForFile.encryptedFile(is, fos, key);
                }
            }
        } catch (FileUploadException e) {
            e.printStackTrace();
        }
        response.setContentType("application/json;charset=utf-8");
        PrintWriter out = response.getWriter();
        out.write(JSON.toJSONString(fileInfo.getUuid()));
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}
